
#include <QDebug>
#include <QFile>
#include <stdio.h>
#include <string.h>
#include "Wave.h"
#include "math.h"


CWave::CWave(void)
{
    // Init members
    clear();
}

CWave::~CWave(void)
{

}

bool CWave::load(const QString &filePath)
{
    bool bResult = true;
    clear();

    // Load .WAV file
    QFile file(filePath);
    if (file.open(QIODevice::ReadOnly))
        {
            // Read .WAV descriptor
            file.read((char*)&m_Descriptor, sizeof(_WAVEDESCR));

            // Check for valid .WAV file
            if (strncmp((char*)m_Descriptor.wave, "WAVE", 4) == 0)
                {
                    // Read .WAV format
                    file.read((char*)&m_Format.id, 4);
                    file.read((char*)&m_Format.size, 4);
                    file.read((char*)&m_Format.format, 2);
                    file.read((char*)&m_Format.channels, 2);
                    file.read((char*)&m_Format.sampleRate, 4);
                    file.read((char*)&m_Format.byteRate, 4);
                    file.read((char*)&m_Format.blockAlign, 2);
                    file.read((char*)&m_Format.bitsPerSample, 2);
                    if(m_Format.size > 16)
                        file.read((char*)&m_Format.extraFormatBytes, 2);
                    else
                        m_Format.extraFormatBytes = 0;

                    if(m_Format.extraFormatBytes)
                        {
                            char c;
                            for(uint16_t i = 0 ; i < m_Format.extraFormatBytes; ++i)
                                file.read(&c, 1);
                        }

                    // Check for valid .WAV file
                    if ( (strncmp((char*)m_Format.id, "fmt", 3) == 0) && (m_Format.format == 1) )
                        {
                            // Read next chunk
                            char id[4];
                            uint32_t size;
                            file.read((char*)id, sizeof(char)*4);
                            file.read((char*)&size, sizeof(uint32_t));
                            uint32_t offset = file.pos();

                            // Read .WAV data
                            QByteArray lTemp;
                            while (offset < m_Descriptor.size)
                                {
                                    // Check for .WAV data chunk
                                    if (strncmp((char*)id, "data", 4) == 0)
                                        m_data = file.read(sizeof(char)*size);
                                    else
                                        lTemp = file.read(sizeof(char)*size);

                                    // Read next chunk
                                    file.read((char*)id, sizeof(char)*4);
                                    file.read((char*)&size, sizeof(uint32_t));
                                    offset = file.pos();
                                }
                        }
                }

            // Close .WAV file
            file.close();
        }
    else
        {
            bResult = false;
            qDebug()<<"can not open file";
        }

    return bResult;
}

bool CWave::Save(const QString& filePath)
{
    bool bResult = false;

	// Save .WAV file
    QFile file(filePath);

    if (file.open(QIODevice::WriteOnly))
        {
            fillDescriptor();
            // Save .WAV descriptor
            file.write((char*)&m_Descriptor, sizeof(_WAVEDESCR));

            // Save .WAV format
            file.write((char*)&m_Format, sizeof(_WAVEFORMAT));

            // Write .WAV data
            char id[4] = {'d', 'a', 't', 'a'};
            uint32_t dwSize = m_data.size();
            file.write((char*)id, sizeof(char)* 4);
            file.write((char*)&dwSize, sizeof(uint32_t));
            file.write(m_data.data(), m_data.size());
            bResult = true;
            m_name = filePath;

            // Close .WAV file
            file.close();
        }

        return bResult;
}

bool CWave::Mix(CWave& /*wave*/)
{
    bool bResult = false;

/*	// Check for valid sound data
    if (IsValid() && wave.IsValid())
	{
		// Check for valid sound format
		if ((m_Format.channels == wave.GetChannels()) && (m_Format.sampleRate == wave.GetSampleRate()) && (m_Format.bitsPerSample == wave.GetBitsPerSample()))
		{
			// Mix .WAVs
            long sampleSize = min(m_data.size(), wave.GetSize()) / (m_Format.bitsPerSample >> 3);
			switch (m_Format.bitsPerSample)
			{
				case 8:
					{
						LPBYTE lpSrcData = wave.GetData();
						LPBYTE lpDstData = m_lpData;
						float gain = log10(20.0f);
						for (long i=0; i<sampleSize; i++)
						{
							*lpDstData = (BYTE)(((*lpSrcData+*lpDstData)>>1)*gain);
							lpSrcData++;
							lpDstData++;
						}
					}
					break;

				case 16:
					{
						LPWORD lpSrcData = (LPWORD)wave.GetData();
						LPWORD lpDstData = (LPWORD)m_lpData;
						for (long i=0; i<sampleSize; i++)
						{
							float sample1 = (*lpSrcData - 32768) / 32768.0f;
							float sample2 = (*lpDstData - 32768) / 32768.0f;
							if (fabs(sample1*sample2) > 0.25f)
								*lpDstData = (WORD)(*lpSrcData + *lpDstData);
							else
								*lpDstData = fabs(sample1) < fabs(sample2) ? *lpSrcData : *lpDstData;
							lpSrcData++;
							lpDstData++;
						}
					}
					break;
			}
			bResult = TRUE;
		}
	}
*/
    return bResult;
}

void CWave::setData(char *data, uint32_t size)
{
    m_data.clear();
    m_data.resize(size);
    for(uint32_t i = 0; i < size; ++i)
        m_data[i] = data[i];
}

void CWave::fillDescriptor()
{
    memset(&m_Descriptor, 0, sizeof(_WAVEDESCR));
    strncpy(reinterpret_cast<char *>(&m_Descriptor.riff[0]),"RIFF",4);
    strncpy(reinterpret_cast<char *>(&m_Descriptor.wave[0]),"WAVE",4);
    m_Descriptor.size = m_data.size()+sizeof(char)*4+sizeof(uint32_t) + sizeof(_WAVEFORMAT);
}

void CWave::fillFormat()
{
    /*
    char  id[4];
    uint32_t size;
    uint16_t format;
    uint16_t channels;
    uint32_t sampleRate;
    uint32_t byteRate;
    uint16_t blockAlign;
    uint16_t bitsPerSample;
    uint16_t extraFormatBytes;
     **/
    memset(&m_Format, 0, sizeof(_WAVEFORMAT));
    strncpy(reinterpret_cast<char *>(&m_Format.id[0]),"fmt",3);
    m_Format.size = sizeof(_WAVEFORMAT);
    m_Format.format = 1 ;// PCM uncompressed
    m_Format.channels = 1;
}

void CWave::clear()
{
    memset(&m_Descriptor, 0, sizeof(_WAVEDESCR));
    memset(&m_Format, 0, sizeof(_WAVEFORMAT));
    m_data.clear();
}

